/**
 * 左移、右移操作
 * User: Zhikang.Peng
 * Date: 2018/04/11 15:52
 */
package math

import (
	"gitee.com/thghh/jvmgo/instructions/base"
	"gitee.com/thghh/jvmgo/rtda"
)

//将int型数值左移位指定位数并将结果压入栈顶
type ISHL struct{ base.NoOperandsInstruction }

func (self *ISHL) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	// v1是要进行位移操作的变量，v2指出要移位多少比特
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	// int变量只有32位，所以只取v2的前5个比特就足够表示位移位数了
	// Go语言位移操作符右侧必须是无符号整数，所以需要对v2进行类型转换
	s := uint32(v2) & 0x1f
	result := v1 << s
	stack.PushInt(result)
}

//将long型数值左移位指定位数并将结果压入栈顶
type LSHL struct{ base.NoOperandsInstruction }

func (self *LSHL) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := uint32(v2) & 0x3f
	result := v1 << s
	stack.PushLong(result)
}

//将int型数值右（符号）移位指定位数并将结果压入栈顶
type ISHR struct{ base.NoOperandsInstruction }

func (self *ISHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := uint32(v2) & 0x1f
	result := v1 >> s
	stack.PushInt(result)
}

//将long型数值右（符号）移位指定位数并将结果压入栈顶
type LSHR struct{ base.NoOperandsInstruction }

func (self *LSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := uint32(v2) & 0x3f
	result := v1 >> s
	stack.PushLong(result)
}

//将int型数值右（无符号）移位指定位数并将结果压入栈顶
type IUSHR struct{ base.NoOperandsInstruction }

/**
Go语言并没有Java语言中的>>>运算符，为了达到无符号位移
的目的，需要先把v1转成无符号整数，位移操作之后，再转回有符
号整数。
*/
func (self *IUSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := uint32(v2) & 0x1f
	result := int32(uint32(v1) >> s)
	stack.PushInt(result)
}

//将long型数值右（无符号）移位指定位数并将结果压入栈顶
type LUSHR struct{ base.NoOperandsInstruction }

func (self *LUSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := uint32(v2) & 0x3f
	result := int64(uint64(v1) >> s)
	stack.PushLong(result)
}
